﻿using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.EntityFrameworkCore;
using OnlineStore.Data;
using OnlineStore.Models;

namespace OnlineStore.Services.Support
{
    public class AccountService : IAccountService
    {
        private readonly OnlineStoreDbContext _context;

        public AccountService(OnlineStoreDbContext context)
        {
            _context = context;
        }

        public async Task<ClaimsPrincipal> AdminLoginAsync(Admin admin)
        {
            var adminInContext = await _context.Admins.FirstOrDefaultAsync(a => a.Email == admin.Email);
            if (adminInContext == null)
            {
                throw new EmailNotFoundException();
            }

            if (adminInContext.Password != admin.Password)
            {
                throw new PasswordErrorException();
            }

            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Email, adminInContext.Email),
                new Claim(ClaimTypes.Name, adminInContext.UserName),
                new Claim("Id", adminInContext.Id.ToString()),
                new Claim(ClaimTypes.Role, "Admin")
            };
            var claimIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

            return await Task.FromResult(new ClaimsPrincipal(claimIdentity));
        }

        public async Task AdminRegisterAsync(Admin admin)
        {
            var exist = await _context.Admins.FirstOrDefaultAsync(a => a.Email == admin.Email);
            if (exist != null)
            {
                throw new EmailExistException();
            }

            await _context.Admins.AddAsync(admin);
            _context.SaveChanges();
        }

        public async Task<ClaimsPrincipal> UserLoginAsync(User user)
        {
            var userInContext = await _context.Users.FirstOrDefaultAsync(u => u.Email == user.Email);
            if (userInContext == null)
            {
                throw new EmailNotFoundException();
            }

            if (userInContext.Password != user.Password)
            {
                throw new PasswordErrorException();
            }

            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Email, userInContext.Email),
                new Claim(ClaimTypes.Name, userInContext.Name),
                new Claim("Id", userInContext.Id.ToString()),
            };
            var claimIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

            return await Task.FromResult(new ClaimsPrincipal(claimIdentity));
        }

        public async Task UserRegister(User user)
        {
            var exist = await _context.Users.FirstOrDefaultAsync(u => u.Email == user.Email);
            if (exist != null)
            {
                throw new EmailExistException();
            }

            await _context.Users.AddAsync(user);
            _context.SaveChanges();
        }

        public async Task UserChangeInfo(User user)
        {
            var exist = await _context.Users.FirstOrDefaultAsync(u => u.Email == user.Email);
            if (exist != null)
            {
                throw new EmailExistException();
            }
            _context.Users.Update(user);
            await _context.SaveChangesAsync();
        }

        public async Task AdminChangeInfo(Admin admin)
        {
            _context.Admins.Update(admin);
            await _context.SaveChangesAsync();
        }

        public async Task UserAddContact(int userId, ContactInfo contact)
        {
            // 查找到指定的用户
            var user = await _context.Users.FindAsync(userId);
            Debug.Assert(user != null, $"{nameof(UserAddContact)} user == null");

            // 将contact 加入数据库中
            contact.User = user;
            await _context.ContactInfos.AddAsync(contact);
        }

        public IEnumerable<ContactInfo> GetUserContactInfo(int userId)
        {
            var infos = _context.ContactInfos
                .Where(info => info.UserId == userId).AsEnumerable();
            return infos;
        }

        public IEnumerable<ContactInfo> GetAdminContactInfo(int adminId)
        {
            var infos = _context.ContactInfos.Where(info => info.AdminId == adminId)
                .AsEnumerable();
            return infos;
        }

        public async Task AdminAddContact(int adminId, ContactInfo contact)
        {
            var admin = await _context.Admins.FindAsync(adminId);
            Debug.Assert(admin != null, $"{nameof(UserAddContact)} admin == null");

            contact.Admin = admin;
            await _context.ContactInfos.AddAsync(contact);
        }

        public Admin FindAdminByEmail(string email)
        {
            var adminInContext = _context.Admins.FirstOrDefault(admin => admin.Email == email);
            Debug.Assert(adminInContext != null);
            return adminInContext;
        }

        public IEnumerable<User> FindAllUser()
        {
            var users = _context.Users.Select(user => user);
            return users.ToList();
        }
    }
}